package com.gitee.flwwsg.rpc.client;

import com.gitee.flwwsg.rpc.transport.Transport;
import com.itranswarp.compiler.JavaStringCompiler;
import lombok.NoArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

public class DynamicStubFactory implements StubFactory {
    private static final Logger logger = LoggerFactory.getLogger(DynamicStubFactory.class);

    // 使用 jdk 11 以后，该警告消失。FIXME 存在警告: Can't initialize javac processor due to (most likely) a class loader problem: java.lang.NoClassDefFoundError: com/sun/tools/javac/processing/JavacProcessingEnvironment
    private final static String STUB_SOURCE_TEMPLATE =
            "package com.gitee.flwwsg.rpc.client.stubs;\n" +
            "import com.gitee.flwwsg.rpc.serialize.SerializeSupport;\n" +
            "\n"+
            "public class %s extends AbstractStub implements %s {\n" +
            "   @Override\n" +
            "   public String %s(String arg) {\n" +
            "       return SerializeSupport.parse(\n" +
            "               invokeRemote(\n" +
            "                       new RPCRequest(\n" +
            "                              \"%s\", \n" +
            "                              \"%s\", \n" +
            "                              SerializeSupport.serialize(arg) \n" +
            "               )\n" +
            "          )\n" +
            "       );\n" +
            "   }\n" +
            "}";
    //加法的模板
    private final static String STUB_SOURCE_ADD_TEMPLATE =
            "package com.gitee.flwwsg.rpc.client.stubs;\n" +
            "import com.gitee.flwwsg.rpc.serialize.SerializeSupport;\n" +
            "\n"+
            "public class %s extends AbstractStub implements %s {\n" +
            "   @Override\n" +
            "   public Integer %s(Integer arg) {\n" +
            "       return SerializeSupport.parse(\n" +
            "               invokeRemote(\n" +
            "                       new RPCRequest(\n" +
            "                              \"%s\", \n" +
            "                              \"%s\", \n" +
            "                              SerializeSupport.serialize(arg) \n" +
            "               )\n" +
            "          )\n" +
            "       );\n" +
            "   }\n" +
            "}";

    @Override
    @SuppressWarnings("unchecked")
    public <T> T createStub(Transport transport, Class<T> serviceClass) {
        try {
            String stubSimpleName = serviceClass.getSimpleName() + "Stub";
            String classFullName = serviceClass.getName();
            String stubFullName = "com.gitee.flwwsg.rpc.client.stubs." + stubSimpleName;
            String methodName = serviceClass.getMethods()[0].getName();
            String className = serviceClass.getCanonicalName();
            String source;
            if (className.equals("com.gitee.flwwsg.rcp.service.HelloService")) {
                source = String.format(STUB_SOURCE_TEMPLATE, stubSimpleName, classFullName, methodName, classFullName, methodName);
            } else {
                source = String.format(STUB_SOURCE_ADD_TEMPLATE, stubSimpleName, classFullName, methodName, classFullName, methodName);
            }
            JavaStringCompiler compiler = new JavaStringCompiler();
            //编译源代码
            Map<String, byte[]> results = compiler.compile(stubSimpleName + ".java", source);
            //加载编译好的类
            Class<?> clazz = compiler.loadClass(stubFullName, results);
            ServiceStub stubInstance = (ServiceStub) clazz.getDeclaredConstructor().newInstance();
            stubInstance.setTransport(transport);
            //返回桩
            return (T) stubInstance;
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }
}
